package cn.org.donald.sensitive.factory;

import cn.org.donald.sensitive.model.FactoryEnum;
import cn.org.donald.sensitive.util.ExcelUtil;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.NumberToTextConverter;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Donald
 * @since 2023-11-10 15:41:15
 **/
public class ExcelFindSensitive extends IFindSensitive {

    public ExcelFindSensitive(Path filePath, FactoryEnum factoryEnum) {
        super(filePath, factoryEnum);
    }

    @Override
    public List<String> getSensitiveString(List<String> ruleRegexList) {
        // 查看是那种类型的excel
        FactoryEnum factoryEnum = super.getFactoryEnum();
        List<String> list = new ArrayList<>();
        Path filePath = super.getFilePath();
        try (InputStream inputStream = Files.newInputStream(filePath)) {
            if (FactoryEnum.XLS.equals(factoryEnum)) {
                findXls(inputStream, ruleRegexList, list);
            } else {
                findXlsx(inputStream, ruleRegexList, list);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return list;
    }

    @Override
    public void replace(List<String> ruleRegexList, Path destPath) {
        String regex = String.join("|", ruleRegexList);
        try {
            Files.deleteIfExists(destPath);
            Files.createDirectories(destPath.getParent());
            Files.createFile(destPath);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        try (InputStream inputStream = Files.newInputStream(super.getFilePath())) {
            Workbook workbook;
            if (FactoryEnum.XLSX.equals(super.getFactoryEnum())) {
                workbook = new XSSFWorkbook(inputStream);
            } else if (FactoryEnum.XLS.equals(super.getFactoryEnum())) {
                workbook = new HSSFWorkbook(inputStream);
            } else {
                throw new RuntimeException("无法解析该文件【" + destPath + "】");
            }
            ExcelUtil.doReplace(workbook, destPath, regex);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private void findXls(InputStream inputStream, List<String> ruleRegexList, List<String> result) {
        try (HSSFWorkbook sheets = new HSSFWorkbook(inputStream)) {
            for (int i = 0; i < sheets.getNumberOfSheets(); i++) {
                HSSFSheet hssfSheet = sheets.getSheetAt(i);
                hssfSheet.rowIterator().forEachRemaining(row -> row.cellIterator().forEachRemaining(cell -> {
                    if (cell == null) return;
                    String cellValString = ExcelUtil.getCellValString(cell);
                    result.addAll(super.findSensitiveInString(ruleRegexList, cellValString).collect(Collectors.toList()));
                }));
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private void findXlsx(InputStream inputStream, List<String> ruleRegexList, List<String> result) {
        try (XSSFWorkbook sheets = new XSSFWorkbook(inputStream)) {
            for (int i = 0; i < sheets.getNumberOfSheets(); i++) {
                XSSFSheet xssfSheet = sheets.getSheetAt(i);
                xssfSheet.rowIterator().forEachRemaining(row -> row.cellIterator().forEachRemaining(cell -> {
                    if (cell == null) return;
                    String cellValString = ExcelUtil.getCellValString(cell);
                    result.addAll(super.findSensitiveInString(ruleRegexList, cellValString).collect(Collectors.toList()));
                }));
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
